#ifndef _TWITTER_VALUEPRINT_H_
#define _TWITTER_VALUEPRINT_H_
#include <twit/Value.h>

NS_BEGIN(Twit)
struct IPrinter
{
   virtual void Print(const char* name, const char* value)=0;
};


#include <stdio.h>

#define pnt(nDepth) for(size_t i=0; i<nDepth; i++) printf("\t"); printf

template<typename T> 
void PrintValue(T& obj, size_t depth=0)
{
}

#define TAB "\t"
class Printer
{
public:
   static void print(size_t depth, const char* name, const int value)
   {
      for(size_t i=0; i<depth; i++)
         printf(TAB);
      printf("%s : %d\n", name, value);
   }
   static void print(size_t depth, const char* name, const char* value)
   {
      for(size_t i=0; i<depth; i++)
         printf(TAB);
      printf("%s : %s\n", name, value?value:"null");
   }
   static void print(size_t depth, const char* name, const std::string& value)
   {
      for(size_t i=0; i<depth; i++)
         printf(TAB);
      printf("%s : %s\n", name, value.c_str());
   }
   static void print(size_t depth, const char* name, const bool& value)
   {
      for(size_t i=0; i<depth; i++)
         printf("  ");
      printf("%s : %s\n", name, value?"true":"false");
   }

   static  void toStatuses(Value::Statuses& v, size_t depth=0)
   {
      print(depth, "statuses",v.empty()?"null":" ");
      
      if(!v.empty())
      {
         depth++;
         for(size_t idx=0; idx<v.size(); idx++)
            toStatus(v[idx], depth);
      }
   }
   static void toDirectMessages(Value::DirectMessages& v, size_t depth=0)
   {
      print(depth, "direct messages", v.empty()?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toDirectMessage(v[i],depth);
      }
   }
   static void toDirectMessage(Value::DirectMessage& v, size_t depth=0)
   {
      print(depth, "direct message", v.isNull()?"null":" ");
      depth++;
      toTime(v.getCreatedAt(), depth, "createdAt");
      print(depth, "id", v.getId().toString().c_str());
      toUser(v.getRecipient(),depth,"recipient");
      print(depth, "recipientID",v.getRecipientId().toString());
      print(depth, "recipientScreenName",v.getRecipientScreenName());
      toUser(v.getSender(), depth, "sender");
      print(depth, "senderID", v.getSenderId().toString());
      print(depth, "senderScreenName",v.getSenderScreenName());
      print(depth, "text", Convert::UnicodeToUtf8(v.getText()));
   }
   static void toStatus(Value::Status* v, size_t depth=0, const char* name="status")
   {
      if(v) toStatus(*v, depth, name);
   }
   static void toStatus(Value::Status& v, size_t depth=0, const char* name="status")
   {
      print(depth, name ,v.isNull()?"null":" ");
      depth++;
      toIDs(v.getContributors(), depth);
      toTime(v.getCreatedAt(), depth, "CreatedAt");
      toEntities(v.getEntities(), depth);
      print(depth,"id",v.getId().toString().c_str());
      print(depth,"in reply to screenName", v.getInReplyToScreenName().c_str());
      print(depth,"in reply to statusID", v.getInReplyToStatusId().toString().c_str());
      print(depth,"in reply to userID", v.getInReplyToUserId().toString().c_str());
      toPlace(v.getPlace(),depth);
      print(depth,"retweetCount",v.getRetweetCount());
      toStatus(v.getRetweetedStatus(),depth,"retweeted status");
      print(depth,"source",Convert::UnicodeToUtf8(v.getSource()));
      print(depth,"text", Convert::UnicodeToUtf8(v.getText()));
      toUser(v.getUser(),depth);
      print(depth,"favorited", v.isFavorited());
      print(depth,"retweeted", v.isRetweeted());
      print(depth,"truncated", v.isTruncated());
   }
   static void toUsers(Value::Users& v, size_t depth=0)
   {
      print(depth, "users", v.empty() ?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toUser(v[i],depth);
      }
   }
   static void toUser(Value::User* v, size_t depth=0, const char* name="user")
   {
      if(v) toUser(*v, depth, name);
   }
   static void toUser(Value::User& v, size_t depth=0, const char* name="user")
   {
      print(depth,name, v.isNull()?"null":" ");
      depth++;
      toTime(v.getCreatedAt(), depth, "CreatedAt");
      print(depth, "description", Convert::UnicodeToUtf8(v.getDescription()));
      print(depth, "favourites count", v.getFavouritesCount());
      print(depth, "followers count", v.getFollowersCount());
      print(depth, "friends count", v.getFriendsCount());
      print(depth, "id", v.getId().toString());
      print(depth, "lang", v.getLanguage());
      print(depth, "location", Convert::UnicodeToUtf8(v.getLocation()));
      print(depth, "name", Convert::UnicodeToUtf8(v.getName()));
      print(depth, "profileBackGroundColor", v.getProfileBackgroundColor().toString());
      print(depth, "profileBackgroundImageUrl",v.getProfileBackgroundImageUrl());
      print(depth, "profileImageUrl", v.getProfileImageUrl());
      print(depth, "profileLinkColor", v.getProfileLinkColor().toString());
      print(depth, "profileSidebarBorderColor", v.getProfileSidebarBorderColor().toString());
      print(depth, "profileSidebarFillColor",v.getProfileSidebarFillColor().toString());
      print(depth, "profileTextColor", v.getProfileTextColor().toString());
      print(depth, "screen name", v.getScreenName());
      toStatus(v.getStatus(), depth);
      print(depth, "statuses count", v.getStatusesCount());
      print(depth, "time zone", v.getTimeZone());
      print(depth, "url", v.getUrl());
      print(depth, "utfOffset", v.getUtcOffset());
      print(depth, "contributors enabled", v.isContributorsEnabled());
      print(depth, "followling", v.isFollowling());
      print(depth, "followRequestSent", v.isFollowRequestSent());
      print(depth, "geo enabled", v.isGeoEnabled());
      print(depth, "notifications", v.isNotifications());
      print(depth, "profileBackgroundTiled",v.isProfileBackgroundTiled());
      print(depth, "profileUseBackgroundImage", v.isProfileUseBackgroundImage());
      print(depth, "protected",v.isProtected());
      print(depth, "showAllInlineMedia",v.isShowAllInlineMedia());
      print(depth, "verified",v.isVerified());
   }
   static void toPlace(Value::Place* v, size_t depth=0)
   {
      if(v) toPlace(*v, depth);
   }
   static void toPlace(Value::Place& v, size_t depth=0)
   {
      print(depth,"place", v.isNull()?"null":" ");
      depth++;
      toPlaces(v.getContainedWithin(), depth,"containedWithIn");
      print(depth,"country",Convert::UnicodeToUtf8(v.getCountry()).c_str());
      print(depth,"country code", v.getCountryCode().c_str());
      print(depth,"full name", Convert::UnicodeToUtf8(v.getFullName()).c_str());
      print(depth,"id", v.getId().c_str());
      print(depth,"name",Convert::UnicodeToUtf8(v.getName()).c_str());
      print(depth,"placeType",v.getPlaceType().c_str());
      print(depth,"url",v.getUrl().c_str());
   }
   static void toPlaces(Value::Places& v, size_t depth=0, const char* name="places")
   {
      print(depth,name,v.empty()?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toPlace(v[i], depth);
      }
   }

   static void toEntities(Value::Entities& v, size_t depth=0)
   {
      print(depth, "entities", v.isNull()?"null":" ");
      if(!v.isNull())
      {
         depth++;
         toHashTags(v.getHashTags(), depth);
         toUrls(v.getUrls(), depth);
         toUserMentions(v.getUserMentions(), depth);
      }
   }

   static void toUserMentions(Value::UserMentions& v, size_t depth=0)
   {
      print(depth, "user mentions", v.empty() ? "null":" ");
      
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toUserMention(v[i],depth);
      }
   }

   static void toUserMention(Value::UserMention& v, size_t depth=0)
   {
      print(depth, "user mention", v.isNull() ? "null":" ");
      depth++;
      print(depth,"start",(int)v.getStart());
      print(depth,"end",(int)v.getEnd());
      print(depth,"name", Convert::UnicodeToUtf8(v.getName()).c_str());
      print(depth,"screen name", v.getScreenName().c_str());
      print(depth,"id",v.getId().toString().c_str());
   }

   static void toUrls(Value::Urls& v, size_t depth=0)
   {
      print(depth, "urls", v.empty()?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toUrl(v[i],depth);
      }
   }

   static void toUrl(Value::Url& v, size_t depth=0)
   {
      print(depth, "url", v.isNull()?"null":" ");
      depth++;
      print(depth, "start",(int)v.getStart());
      print(depth, "end",(int)v.getEnd());
      print(depth, "url",v.getUrl().c_str());
      print(depth, "expanded url", v.getExpandedUrl().c_str());
   }

   static void toHashTags(Value::HashTags& v, size_t depth=0)
   {
      print(depth, "hashtags",v.empty()?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toHashTag(v[i], depth);
      }
   }

   static void toHashTag(Value::HashTag& v, size_t depth=0)
   {
      print(depth, "hashtag", v.isNull()?"null":" ");
      depth++;
      print(depth, "start", (int)v.getStart());
      print(depth, "end", (int)v.getEnd());
      print(depth, "text", Convert::UnicodeToUtf8(v.getText()).c_str());
   }

   static void toTime(Value::Time& v, size_t depth=0, const char* name="time")
   {
      print(depth,name, v.toString().c_str());
   }

   static void toIDs(Value::IDs& v, size_t depth=0, const char* name="IDs")
   {
      print(depth, name, v.empty()?"null":" ");
      
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            print(depth," ",v[i].toString().c_str());
      }
   }

   static void toCategories(Value::Categories& v, size_t depth=0)
   {
      print(depth, "categories", v.empty()?"null":" ");
      if(v.size())
      {
         depth++;
         for(size_t i=0; i<v.size(); i++)
            toCategory(v[i], depth);
      }
   }

   static void toCategory(Value::Category& v, size_t depth=0)
   {
      if(v.isNull()) return;
      print(depth, "name", v.getName());
      print(depth, "slug", v.getSlug());
   }

   static void toList(Value::List& v, size_t depth=0)
   {
      print(depth, "list", v.isNull()?"null":" ");
      depth++;
      print(depth, "description", Convert::UnicodeToUtf8(v.getDescription()) );
      print(depth, "full name", v.getFullName() );
      print(depth, "id", v.getId().toString());
      print(depth, "member count", v.getMemberCount());
      print(depth, "mode", v.getMode());
      print(depth, "name", Convert::UnicodeToUtf8(v.getName()));
      print(depth, "slug", Convert::UnicodeToUtf8(v.getSlug()));
      print(depth, "subscriber count", v.getSubscriberCount());
      print(depth, "uri", v.getUri());
      toUser(v.getUser(), depth);
      print(depth, "followling", v.isFollowing());
   }

   static void toLists(Value::Lists& v, size_t depth=0)
   {
      print(depth, "lists", v.empty() ? "null":" ");
      if(v.size())
      {
         depth++;
         print(depth, "next cursor", v.getNextCursor());
         print(depth, "previous cursor", v.getPreviousCursor());

         for(size_t i=0; i<v.size(); i++)
            toList(v[i], depth);
      }
   }
};
NS_END;
#endif /*_TWITTER_VALUEPRINT_H_*/

